package com.chhuang.tutool.socket

import android.util.Log
import com.chhuang.tutool.socket.base.ISendable
import com.gnetek.tool.socket.NettyClient
import com.swallowsonny.convertextlibrary.toAsciiString
import com.swallowsonny.convertextlibrary.toHexString
import io.netty.bootstrap.ServerBootstrap
import io.netty.buffer.ByteBuf
import io.netty.buffer.Unpooled
import io.netty.channel.*
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.SocketChannel
import io.netty.channel.socket.nio.NioServerSocketChannel
import java.net.InetSocketAddress
import java.nio.charset.Charset


class NettyServer(
    port: Int,
    private val success:(server: NettyServer)->Unit,
    private val failed:()->Unit,
    private val received:(content: ByteArray, ip:String, port:Int)->Unit,
    private val updateChannels: (channelMap: MutableMap<String, SocketChannel>)->Unit) {

    companion object{
        private const val TAG = "NettyServer"

        /**
         * boss 线程组用于处理连接工作
         */
        private var bossGroup: NioEventLoopGroup? = null

        /**
         * work 线程组用于数据处理
         */
        private var workGroup: NioEventLoopGroup? = null

        private var channelFuture: ChannelFuture? = null

        /**
         * 连上服务器的客户端map
         */
        private val channelMap = mutableMapOf<String, SocketChannel>()


        /**
         * 本地服务器地址
         */
        private var loaclInetSocketAddress: InetSocketAddress? = null

    }

    private var run = false

    init {
        bossGroup= NioEventLoopGroup()
        workGroup= NioEventLoopGroup()

        val b = ServerBootstrap()
        b.group(bossGroup, workGroup)
            .channel(NioServerSocketChannel::class.java)
            .localAddress(port)
            .option(ChannelOption.SO_BACKLOG, 256)//服务端接受连接的队列长度，如果队列已满，客户端连接将被拒绝
            .option(ChannelOption.RCVBUF_ALLOCATOR, AdaptiveRecvByteBufAllocator(3069, 4096, 65536))//设置tcp缓冲区 有用
            .childOption(ChannelOption.SO_KEEPALIVE, true)
            .childOption(ChannelOption.TCP_NODELAY, true)
            .childHandler(object : ChannelInitializer<SocketChannel>(){
                override fun initChannel(ch: SocketChannel?) {
                    ch?.pipeline()?.addLast(object: SimpleChannelInboundHandler<ByteBuf>(){
                        override fun messageReceived(ctx: ChannelHandlerContext?, msg: ByteBuf?) {
                            ctx?.let {
                                val channel = it.channel() as SocketChannel
                                val remote = channel.remoteAddress()
                                val ip = remote.address.hostAddress!!
                                val rport = remote.port
                                Log.e(TAG, "messageReceived:${ip}:${rport} 发来的消息接收成功")
                                msg?.let {
                                    val len = it.readableBytes() //数据长度
                                    val datas = ByteArray(len)
                                    it.readBytes(datas) // 接收的数据

                                    val content: String = datas.toHexString()
                                    Log.e(TAG, """tcpServer: received msg = ${content}""")
                                    val ascii: String = datas.toAsciiString()
                                    Log.e(TAG, """tcpServer: received ascii msg = ${ascii}""")

                                    val utf8: String = String(datas, Charsets.UTF_8)
                                    Log.e(TAG, """tcpServer: received ascii msg = ${utf8}""")
                                    val gbk: String = String(datas, Charset.forName("GBK"))
                                    Log.e(TAG, """tcpServer: received ascii msg = ${gbk}""")

                                    received(datas, ip, port)
                                }
                            }
                        }

                        /**
                         * 客户端创建连接
                         */
                        override fun channelActive(ctx: ChannelHandlerContext?) {
                            ctx?.let {
                                val channel = it.channel() as SocketChannel
                                val remote = channel.remoteAddress()
                                val ip = remote.address.hostAddress
                                val rport = remote.port
                                Log.e(TAG, "channelActive: ${ip}:${rport} 连上服务器", )
                                if(loaclInetSocketAddress==null) loaclInetSocketAddress = channel.localAddress()
                                //获取连接通道唯一标识
                                val sessionId = channel.id().asShortText()
                                if(!channelMap.containsKey(sessionId)){
                                    channelMap.put(sessionId, channel)
                                    updateChannels(channelMap)
                                }
                            }

                            super.channelActive(ctx)
                        }

                        /**
                         * 客户端正常退出
                         */
                        override fun channelInactive(ctx: ChannelHandlerContext?) {
                            ctx?.let {
                                val channel = it.channel() as SocketChannel
                                val remote = channel.remoteAddress()
                                val ip = remote.address.hostAddress
                                val rport = remote.port
                                Log.e(TAG, "channelActive: ${ip}:${rport} 退出服务器连接", )
                                //获取连接通道唯一标识
                                val sessionId = channel.id().asShortText()
                                if(channelMap.containsKey(sessionId)){
                                    channelMap.remove(sessionId)
                                    updateChannels(channelMap)
                                }
                            }

                            super.channelInactive(ctx)
                        }

                        /**
                         * 客户端异常退出
                         */
                        override fun exceptionCaught(ctx: ChannelHandlerContext?, cause: Throwable?) {
                            ctx?.let {
                                val channel = it.channel() as SocketChannel
                                val remote = channel.remoteAddress()
                                val ip = remote.address.hostAddress
                                val rport = remote.port
                                Log.e(TAG, "channelActive: ${ip}:${rport} 异常退出服务器连接", )
                                //获取连接通道唯一标识
                                val sessionId = channel.id().asShortText()
                                if(channelMap.containsKey(sessionId)){
                                    channelMap.remove(sessionId)
                                    updateChannels(channelMap)
                                }
                            }

                            super.exceptionCaught(ctx, cause)
                        }
                    })
                }
            })

        try {
            channelFuture = b.bind().addListener {
                if(it.isSuccess){
                    Log.e(TAG, "NettyServer: 启动成功")
                    run = true
                    success(this)
                }else{
                    Log.e(TAG, "NettyServer: 启动失败")
                    failed()
                }
            }.sync()
        } catch (e: InterruptedException) {
            e.printStackTrace()
            Log.e(TAG, "NettyServer: 启动失败")
            failed()
            bossGroup?.shutdownGracefully()?.syncUninterruptibly()
            workGroup?.shutdownGracefully()?.syncUninterruptibly()
        }

    }

    fun isRuning(): Boolean{
        return run
    }

    /**
     * 获取本地ip与port信息
     */
    fun getLocalSocketAddress(): InetSocketAddress?{
        return if(isRuning()) loaclInetSocketAddress else null
    }

    /**
     * 销毁
     */
    fun destory(){
        if(isRuning()){
            bossGroup?.shutdownGracefully()?.syncUninterruptibly()
            workGroup?.shutdownGracefully()?.syncUninterruptibly()
            channelMap.clear()
            channelFuture = null
            run = false
        }
    }

    /**
     * 发送一个的消息，
     */
    fun sendMessage(datas: ByteArray, sessionIds: List<String>){
        if (!isRuning()) {
            return
        }
        for (id in sessionIds){
            val sc = channelMap.get(id)
            sc?.writeAndFlush(Unpooled.copiedBuffer(datas))?.addListener { future ->
                if (future.isSuccess) {
                    //消息发送成功
                    Log.e(TAG, "netty server 消息发送成功")
                } else {
                    //消息发送失败
                    Log.e(TAG, "netty server 消息发送失败")
                }
            }
        }
    }

    /**
     * 发送消息
     */
    fun sendMessage(sendable: ISendable, sessionIds: List<String>) {
        sendMessage(sendable.parse(), sessionIds)
    }
}